/**
 * 
 */
package control;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.util.ArrayList;

import javax.media.jai.JAI;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;

import model.DadosGerais;
import util.AnotationLayer;
import util.MyUtilities;
import view.GuiGeneral;
import view.MenuBarGeneral;
import view.ToolBarInferior;
import view.ToolBarInteractive;
import view.ToolBarSuperior;
import classification.Transfer;


/**
 * Classe responsavel pelo controle geral do sistema.
 * Trata todas as chamadas de acao das GUIs.
 * Armazenas as layers e suas imagens que estao atualmente em uso.
 * 
 * Eh responsavel pela montagem e apresentacao da Janela Principal e da Janela Interava.
 * 
 * @author agnaldo
 *
 */
public class TrataEventosPrincipal implements EventosGUI {
	
	private Dados dadosBackup;
	private BufferedImage imageAnotation;
	private AnotationLayer layer, layerResultado, layerNovaAnotacao;
	private GuiGeneral janelaPrincipal, janelaInterativa;
	private MenuBarGeneral menuBar;
	private ToolBarSuperior toolBarSup;
	private ToolBarInferior toolBarInf;
	private ToolBarInteractive toolBarInter;
	private JInternalFrame janelaInternaResultado, janelaInternaNovaAnotacao;
	private Transfer transferencia;
	boolean flag = false;

	/**
	 * Construtor da classe. 
	 * @param dados 	objeto para backup dos dados - Eh uma instancia unica no programa (criada na classe Main)
	 * 
	 */
	public TrataEventosPrincipal(DadosGerais dados) {
		
		dadosBackup = dados;
		
		//montando Janela Principal
		menuBar = new MenuBarGeneral(this);  
		toolBarSup = new ToolBarSuperior(this);
		toolBarInf = new ToolBarInferior(this);
		
		janelaPrincipal = new GuiGeneral(this, "GUI - Interactive Classification");
		janelaPrincipal.setJMenuBar(menuBar);			//fixando barra de menu na janela
		janelaPrincipal.getContentPane().add(toolBarSup, BorderLayout.NORTH);//inserindo barras de ferramentas
		janelaPrincipal.getContentPane().add(toolBarInf, BorderLayout.SOUTH);
		janelaPrincipal.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // encerrar programa ao fechar janela principal
		
		//montando Janela Interativa
		toolBarInter = new ToolBarInteractive(this);
		janelaInterativa = new GuiGeneral(this, "Interactive Window");
		janelaInterativa.getContentPane().add(toolBarInter, BorderLayout.NORTH);
		
		
	}//fim do construtor
	
	/**
	 * Metodo para tornar a janela Principal visivel na tela
	 * (poderia estar incorporada ao construtor)
	 */
	public void inicialize(){
		janelaPrincipal.setVisible(true);
	}
	
	@Override
	public boolean openImage() {
		
		if (this.selectImage() == true) {
		
			if (dadosBackup.getImage() == null) {
				System.out.println( "não carregou imagem - ponteiro nulo"); 
				System.exit(1);
				}
			
			imageAnotation = MyUtilities.copyImage(dadosBackup.getBufferedImage());
			layer = new AnotationLayer(imageAnotation, new JLabel());
			
			//criar o scroll para efetuar as rolagens de tela caso a imagem seja muito grande
			JScrollPane scroll = new JScrollPane();
			scroll.setViewportView(layer); // adicionar o display dentro da scroll
			
			//criar janela interna para receber a imagem
			JInternalFrame janela = new JInternalFrame("Anotation layer", true, true, true, true);
			janela.add(scroll);
			janela.setSize(700, 600);
			janela.validate();
	
			//incluir janela interna no objeto enviado pela GUI-Principal - obtem JDesktop na classe GuiGeneral
			janelaPrincipal.getJDesktopPane().add(janela); 
			janela.setVisible(true);
			return true;
		}
		return false;
	}

	@Override
	public boolean selectImage() {
		if (flag) {
			showDialog ( 1 );
			return false;
		}
		
		JFileChooser fc = new JFileChooser();
		
		if ( fc.showOpenDialog( fc ) == JFileChooser.APPROVE_OPTION ) {
			
			System.out.println(fc.getSelectedFile().getAbsolutePath());
			
			//criar a planarImage
			dadosBackup.setImage( JAI.create("fileload", fc.getSelectedFile().getAbsolutePath() ));	
			return true;
		}
		return false;
	}
	
	@Override
	public void exitProgramm() {
		System.exit(0);
	}

	@Override
	public void setColorClass(Color novaCor, int classe) {
		if(layerNovaAnotacao == null) {			//verifica se action veio da janela Interavtiva
			layer.setCorAtual(novaCor);
			layer.setClasseAtual(classe);
		} else {
			layerNovaAnotacao.setCorAtual(novaCor);
			layerNovaAnotacao.setClasseAtual(classe);
		}
	}

	@Override
	public boolean isInSelection() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public void setClassCurrent(int classeAtual) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public int getClassCurrent() {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public void modificarZoom(float valorZoom) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void startSelection(boolean ativar) {
		if (ativar){
			if (dadosBackup.getUserAnotation() == null)
				dadosBackup.setUserAnotation(new ArrayList<util.PixelAnotado>());
			layer.setSelectOn(true);
			layer.setListaPixels( dadosBackup.getUserAnotation());
		} else {
			layer.setSelectOn(false);
			dadosBackup.getUserAnotation().clear();
		}
	}

	@Override
	public void startAuto() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void startInteractive() {
		
		dadosBackup.setUserAnotation(layer.getListaPixels()); //salva lista de pixels em Backup
		layer.setSelectOn(false);
		
		if(dadosBackup.getUserAnotation() != null) { //usuário deve ter feito alguma marcação
			
			//cria objeto para transferencia de dados (isto é, a classe vai acessar os módulos de classificação do Jefersson)
			transferencia = new Transfer(dadosBackup);
			
			if(! transferencia.runClassification()) {//manda iniciar a classificação, se receber um FALSE vai retornar sem fazer nada
				System.out.println(" ERROR - ABORTED PROCESS");
				return;  
			}
			// inicia thread que informa 'Aguarde Processando' - em elaboracao
		
			// printa na tela mensangem orientando: finalizar ou melhorar classificação
			showDialog(2);
			BufferedImage mascara = MyUtilities.composeMask(dadosBackup.getBufferedImage(), //imagem original
					dadosBackup.getClassificationResult()); // lista de pixels com o resultado da classificação 
			
			layerResultado = new AnotationLayer(mascara);
			janelaInternaResultado = criaJanelaInterna("Previo Result",layerResultado);
			
			janelaInterativa.getJDesktopPane().add(janelaInternaResultado);
			janelaInterativa.repaint();
			janelaInterativa.setVisible(true);
			
		}
		else System.out.println("Classify some pixels first. No data to continue");
		
	}
	
	/**
	 * Metodo para criar uma nova janela interna
	 * @param titulo	Nome da janela interna
	 * @param layer		informa qual layer serah adiconada na janela interna
	 * @return			retoma a nova janela interna
	 */
	private JInternalFrame criaJanelaInterna(String titulo, AnotationLayer layer) {
		
		//criar o scroll para efetuar as rolagens de tela caso a imagem seja muito grande
		JScrollPane scroll = new JScrollPane();
		scroll.setViewportView(layer); // adicionar o display dentro da scroll
		
		//criar janela interna para receber a imagem
		JInternalFrame janela = new JInternalFrame(titulo, true, true, true, true);
		janela.add(scroll);
		janela.setSize(700, 600);
		janela.setVisible(true);
		
		return janela;
	}

		
	@Override
	public boolean nextIteraction() {   // quando usuario clica em 'Send' na janela Interativa
		
		//janelaInternaNovaAnotacao.setVisible(false);// esconde janela interna com marcações do usuário
		janelaInterativa.getJDesktopPane().remove(janelaInternaNovaAnotacao);
		janelaInternaNovaAnotacao = null;  //descartando a janela usada anteriormente
		
		//dadosBackup.setUserAnotation(layerNovaAnotacao.getListaPixels()); //salva lista de pixels em Backup
		MyUtilities.knnClassification(dadosBackup.getUserAnotation(), layerNovaAnotacao.getListaPixels());
		
		if(dadosBackup.getUserAnotation() != null) { //usuario deve ser feito alguma anotação
			
			//mandar iniciar a classificação
			if(! transferencia.runClassification()) return false;
			// inicia thread que informa 'Aguarde Processando'
			
			showDialog(2);
			BufferedImage mascara = MyUtilities.composeMask(dadosBackup.getBufferedImage(), 
					dadosBackup.getClassificationResult());
			layerResultado = new AnotationLayer( mascara);
			if( janelaInternaResultado == null) {
				janelaInternaResultado = criaJanelaInterna("Previo Result", layerResultado);
				janelaInterativa.getJDesktopPane().add(janelaInternaResultado);
			}
			janelaInternaResultado.setVisible(true);
			janelaInterativa.repaint();
			return true;
		}
		return false;
	}

	@Override
	public void newUserAnotation() { // quando usuario clica em 'Refine' na janela Interativa
		
		//janelaInternaResultado.setVisible(false); //esconde janela interna com resultado prévio
		janelaInterativa.getJDesktopPane().remove(janelaInternaResultado);
		janelaInternaResultado = null; //descartando janela usada anteriormente
		
		//primeira etapa é destacar os pixels que o usuário precisa anotar
		//A função composeMask cria a "mascara" desejada em uma cópia da imagem original
		BufferedImage mascara = MyUtilities.composeMask(dadosBackup.getBufferedImage(), 
						dadosBackup.getUserAnotation());
		layerNovaAnotacao = new AnotationLayer( mascara);
		layerNovaAnotacao.setSelectOn(true);   //permitir desenhar sobre a imagem
		
		if( janelaInternaNovaAnotacao == null) {
			janelaInternaNovaAnotacao = criaJanelaInterna("New Anotation", layerNovaAnotacao);
			janelaInterativa.getJDesktopPane().add(janelaInternaNovaAnotacao);
		}
		
		janelaInternaNovaAnotacao.setVisible(true); // mostra janela com regiões para anotação
		janelaInterativa.repaint();
		//janelaInterativa.setVisible(true);
			
	}

	@Override
	public void finishClassification() {
		flag = true;
		janelaInterativa.dispose();
		janelaInternaResultado.setTitle("Result of the classification");
		janelaPrincipal.getJDesktopPane().add(janelaInternaResultado);
		
		JInternalFrame[] vIFrame =  janelaPrincipal.getJDesktopPane().getAllFrames(); 
		int i = 0;
		for(JInternalFrame jI: vIFrame){
			jI.setSize(630, 700);
			if(i++ == 1)									//printar as 2 janelas lado a lado
				jI.setLocation(630, 0);
		}
		janelaPrincipal.remove(toolBarSup);
		toolBarSup = new ToolBarSuperior(this);
		janelaPrincipal.getContentPane().add(toolBarSup, BorderLayout.NORTH);
		janelaPrincipal.validate();
		janelaPrincipal.repaint();
		
	}

	@Override
	public void cleanData() {
		flag = false;
		janelaPrincipal.getJDesktopPane().removeAll();
		janelaInternaNovaAnotacao = null;
		janelaInternaResultado = null;
		layer = null;
		layerNovaAnotacao = null;
		dadosBackup.clean();
		transferencia = null;
		janelaPrincipal.validate();
		janelaPrincipal.repaint();
	}
	
	/** 
	 *  Metodo para printar mensagens de alerta na tela
	 * @param op	informa qual a mensagem a sem impressa.
	 */
	public void showDialog (int op) {
		String message = null;
		
		switch (op) {
			case 1: 
					message = new String("Click File->New to new Classification Process!"); 
					break;
			case 2: 
					message = new String("Click 'Refine' to better classification or 'Finalize' to finish");
					break;
		}
		
		JOptionPane.showMessageDialog(null, message , "Warning", JOptionPane.INFORMATION_MESSAGE);

	}
	
}//fim da classe
